{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NumPy 中的转置"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 转置\n",
    "在 NumPy 中获得矩阵的转置非常容易。只需访问其“T”属性即可。有一个 transpose() 函数也可以返回同样的结果，但是你很少看到它在任何地方使用，因为输入 T 的方法要简答得多。 :)\n",
    "\n",
    "例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  5,  9],\n",
       "       [ 2,  6, 10],\n",
       "       [ 3,  7, 11],\n",
       "       [ 4,  8, 12]])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])\n",
    "m\n",
    "# 显示以下结果：\n",
    "# array([[ 1,  2,  3,  4],\n",
    "#        [ 5,  6,  7,  8],\n",
    "#        [ 9, 10, 11, 12]])\n",
    "\n",
    "m.T\n",
    "# 显示以下结果：\n",
    "# array([[ 1,  5,  9],\n",
    "#        [ 2,  6, 10],\n",
    "#        [ 3,  7, 11],\n",
    "#        [ 4,  8, 12]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NumPy 在进行转置时不实际移动内存中的任何数据 - 只是改变对原始矩阵的索引方式 - 所以是非常高效的。\n",
    "\n",
    "但是，这也意味着你也要特别注意修改对象的方式，因为它们共享相同的数据。例如，对于上面同一个矩阵 m，我们来创建一个新的变量 m_t 来存储 m 的转置。然后看看如果我们修改 m_t 中的值，会发生什么："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  1,   2,   3,   4],\n",
       "       [  5,   6,   7, 200],\n",
       "       [  9,  10,  11,  12]])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_t = m.T\n",
    "m_t[3][1] = 200\n",
    "m_t\n",
    "# 显示以下结果：\n",
    "# array([[ 1,   5, 9],\n",
    "#        [ 2,   6, 10],\n",
    "#        [ 3,   7, 11],\n",
    "#        [ 4, 200, 12]])\n",
    "\n",
    "m\n",
    "# 显示以下结果：\n",
    "# array([[ 1,  2,  3,   4],\n",
    "#        [ 5,  6,  7, 200],\n",
    "#        [ 9, 10, 11,  12]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意它是如何修改转置和原始矩阵的！这是因为它们共享相同的数据副本。所以记住，将转置视为矩阵的不同视图，而不是完全不同的矩阵。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 实际用例\n",
    "我不想过多讲解关于神经网络的细节，因为你还没有学到它们，但是有一个地方你差不多肯定会用到转置，或者至少考虑使用转置。\n",
    "\n",
    "假设你有以下两个矩阵，称为“inputs”和“weights”"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3, 4)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inputs = np.array([[-0.27,  0.45,  0.64, 0.31]])\n",
    "inputs\n",
    "# 显示以下结果：\n",
    "# array([[-0.27,  0.45,  0.64,  0.31]])\n",
    "\n",
    "inputs.shape\n",
    "# 显示以下结果：\n",
    "# (1, 4)\n",
    "\n",
    "weights = np.array([[0.02, 0.001, -0.03, 0.036], \\\n",
    "    [0.04, -0.003, 0.025, 0.009], [0.012, -0.045, 0.28, -0.067]])\n",
    "\n",
    "weights\n",
    "# 显示以下结果：\n",
    "# array([[ 0.02 ,  0.001, -0.03 ,  0.036],\n",
    "#        [ 0.04 , -0.003,  0.025,  0.009],\n",
    "#        [ 0.012, -0.045,  0.28 , -0.067]])\n",
    "\n",
    "weights.shape\n",
    "# displays the following result:\n",
    "# (3, 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我在这里不会讲解它们的用途，因为你稍后都会学到，但是最终你会想要获得这两个矩阵的矩阵乘积。\n",
    "\n",
    "如果你像现在这样去尝试，会获得一个错误："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "shapes (1,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-5-fb901159d543>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmatmul\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minputs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mweights\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;31m# 显示以下错误：\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;31m# ValueError: shapes (1,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: shapes (1,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)"
     ]
    }
   ],
   "source": [
    "np.matmul(inputs, weights)\n",
    "# 显示以下错误：\n",
    "# ValueError: shapes (1,4) and (3,4) not aligned: 4 (dim 1) != 3 (dim 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果你上了矩阵乘法课，那应该见过这个错误。它报告说形状不兼容，因为左边矩阵的列数 4 不等于右边矩阵的行数 3。\n",
    "\n",
    "所以有问题，但是注意，如果你获取 weights 矩阵的转置，它会："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.01299,  0.00664,  0.13494]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(inputs, weights.T)\n",
    "# 显示以下结果：\n",
    "# array([[-0.01299,  0.00664,  0.13494]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果你获取 ` inputs ` 的转置，并调换它们的顺序也可以，就像我们在视频中展示的那样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.01299],\n",
       "       [ 0.00664],\n",
       "       [ 0.13494]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.matmul(weights, inputs.T)\n",
    "# 显示以下结果：\n",
    "# array([[-0.01299],# \n",
    "#        [ 0.00664],\n",
    "#        [ 0.13494]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这两个答案是彼此的转置，所以你使用的乘法只取决于你想要的输出的形状。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NumPy test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input as Array: [-1  2  7]\n",
      "Input minus min: [0 3 8]\n",
      "Input  Array: [0 0 1]\n",
      "Multiply 1:\n",
      "False\n",
      "Multiply 2:\n",
      "[[14]\n",
      " [32]]\n",
      "Multiply 3:\n",
      "[[ 9 12 15]]\n",
      "Mean == 2.66666666667\n"
     ]
    }
   ],
   "source": [
    "# Use the numpy library\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "def prepare_inputs(inputs):\n",
    "    # TODO: create a 2-dimensional ndarray from the given 1-dimensional list;\n",
    "    #       assign it to input_array\n",
    "    input_array = np.array(inputs)\n",
    "    \n",
    "    # TODO: find the minimum value in input_array and subtract that\n",
    "    #       value from all the elements of input_array. Store the\n",
    "    #       result in inputs_minus_min\n",
    "    inputs_minus_min = input_array - np.min(input_array)\n",
    "\n",
    "    # TODO: find the maximum value in inputs_minus_min and divide\n",
    "    #       all of the values in inputs_minus_min by the maximum value.\n",
    "    #       Store the results in inputs_div_max.\n",
    "    inputs_div_max = inputs_minus_min / np.max(inputs_minus_min)\n",
    "\n",
    "    # return the three arrays we've created\n",
    "    return input_array, inputs_minus_min, inputs_div_max\n",
    "    \n",
    "\n",
    "def multiply_inputs(m1, m2):\n",
    "    # TODO: Check the shapes of the matrices m1 and m2. \n",
    "    #       m1 and m2 will be ndarray objects.\n",
    "    #\n",
    "    #       Return False if the shapes cannot be used for matrix\n",
    "    #       multiplication. You may not use a transpose\n",
    "    if m1.shape[1] != m2.shape[0] and m1.shape[0] != m2.shape[1]:\n",
    "        return False\n",
    "\n",
    "\n",
    "    # TODO: If you have not returned False, then calculate the matrix product\n",
    "    #       of m1 and m2 and return it. Do not use a transpose,\n",
    "    #       but you swap their order if necessary\n",
    "    elif m1.shape[1] == m2.shape[0]:\n",
    "        return np.dot(m1, m2)\n",
    "    else: \n",
    "        return np.dot(m2, m1)\n",
    "    \n",
    "\n",
    "def find_mean(values):\n",
    "    # TODO: Return the average of the values in the given Python list\n",
    "    s = 0\n",
    "    for i in values:\n",
    "        s = s + i\n",
    "    #return s / len(values)\n",
    "    return np.mean(values)\n",
    "\n",
    "\n",
    "input_array, inputs_minus_min, inputs_div_max = prepare_inputs([-1,2,7])\n",
    "print(\"Input as Array: {}\".format(input_array))\n",
    "print(\"Input minus min: {}\".format(inputs_minus_min))\n",
    "print(\"Input  Array: {}\".format(inputs_div_max))\n",
    "\n",
    "print(\"Multiply 1:\\n{}\".format(multiply_inputs(np.array([[1,2,3],[4,5,6]]), np.array([[1],[2],[3],[4]]))))\n",
    "print(\"Multiply 2:\\n{}\".format(multiply_inputs(np.array([[1,2,3],[4,5,6]]), np.array([[1],[2],[3]]))))\n",
    "print(\"Multiply 3:\\n{}\".format(multiply_inputs(np.array([[1,2,3],[4,5,6]]), np.array([[1,2]]))))\n",
    "\n",
    "print(\"Mean == {}\".format(find_mean([1,3,4])))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
